package main

import (
	"math"
	"github.com/pkg/errors"
	"fmt"
)

//哈希表
type HashTable struct{
	Table map[int]*List //映射
	size int  //大小
	cap int //容量
}
//元素
type Item struct{
	key string
	value  interface{}
}
//返回哈希表节点
func NewHashTable(cap int)*HashTable{
	table:=make(map[int]*List,cap)//初始化
	return &HashTable{table,0,cap}
}
func ( ht  *HashTable) Get(key string) (interface{},error){
	index:=ht.pos(key)//索引
	item,err:=ht.find(index,key)//查找数据
	if item==nil{
		return "",errors.New("没有找到")
	}
	return item.value,err
}
func (ht *HashTable) Put(key,value string){
	index:=ht.pos(key)//索引
	if ht.Table[index]==nil{
		ht.Table[index]=NewList()//新建一个节点

	}
	item:=&Item{key,value} //新建插入的对象
	data,err:=ht.find(index,key)
	if err!=nil{
		ht.Table[index].Append(item) //数据插入
		ht.size++
	}else{
		data.value=value//替换
	}



}

func (ht *HashTable) Del(key string)error{
	index :=ht.pos(key)
	mylist:=ht.Table[index]//定位要删除的链表
	var val *Item
	mylist.Each(func(node Node) {
		if node.Value.(*Item).key==key{
			val=node.Value.(*Item) //取出数据
		}
	})
	if val==nil{
		return nil //返回数据
	}
	ht.size--
	return mylist.Remove(val) //s删除

}
//循环哈希表的多个链表，循环每个链表的元素
func (ht *HashTable) Foreach(f func(item *Item)){
	for k:=range ht.Table{
		if ht.Table[k]!=nil{
			ht.Table[k].Each(func(node Node) {
				f(node.Value.(*Item))
			})
		}
	}
}
func (ht *HashTable) pos(s string) int{
	return  hashCode(s)%ht.cap //根据哈希值计算
}
func (ht *HashTable)find (i int,key string)(*Item,error){
	mylist:=ht.Table[i] //每一个哈希值对应一个链表
	var val*Item
	mylist.Each(func(node Node) {
		if node.Value.(*Item).key==key{
			val=node.Value.(*Item) //取出数据
		}
	})
	if val==nil{
		return nil,errors.New("not find")
	}
	return val,nil
}
//根据字符串计算哈希
func hashCode(str  string)int{
	hash:= int32(0)
	for i:=0;i<len(str);i++{
		hash=int32(hash<<5-hash)+int32(str[i])
		hash &=hash //哈希计算
	}
	return int(math.Abs(float64(hash)))
}


func main(){
	ht:=NewHashTable(1000)
	ht.Put("yincheng1","123456")
	ht.Put("yincheng2","1234567")
	ht.Put("yincheng3","1234568")
	ht.Put("yincheng4","1234569")
	ht.Put("yincheng5","1234560")

	ht.Put("yincheng3","abc")
	ht.Del("yincheng3")
	val,err:=ht.Get("yincheng3")
	fmt.Println(val,err)





}
